//
//  CalculatorBrain.swift
//  Calculator
//
//  Created by 李朋 on 2017/6/1.
//  Copyright © 2017年 李朋. All rights reserved.
//

import Foundation

class CalculatorBrain {
    
    fileprivate var accumulator = 0.0
    
    fileprivate let operations:[String: Operation] = [
        "π": Operation.Constant(Double.pi),
        "e": Operation.Constant(M_E),
        "√": Operation.UnaryOperation(sqrt),
        "cos": Operation.UnaryOperation(cos),
        "×": Operation.BinaryOperation({$0 * $1}),
        "+": Operation.BinaryOperation({$0 + $1}),
        "-": Operation.BinaryOperation({$0 - $1}),
        "÷": Operation.BinaryOperation({$0 / $1}),
        "=": Operation.Equals
    ]
    
    
    enum Operation {
        case Constant(Double)
        case UnaryOperation((Double) -> Double)
        case BinaryOperation((Double, Double) -> Double)
        case Equals
    }
    
    func setOperand(operand: Double)  {
        accumulator = operand
    }
    
    func performOperation(symbol: String)  {
        if let operation = operations[symbol] {
            switch operation {
            case .Constant(let value):
                accumulator = value
            case .UnaryOperation(let function):
                accumulator = function(accumulator)
            case .BinaryOperation(let function):
                execuPendingBinaryOperartion()
                pending = PendingBinaryOperationInfo(binaryFunction: function, fristOperand: accumulator)
            case .Equals:
                execuPendingBinaryOperartion()
            }
        }
    }
    
    fileprivate func execuPendingBinaryOperartion() {
        if pending != nil {
            accumulator = pending!.binaryFunction(pending!.fristOperand,accumulator)
            pending = nil
        }
    }
    
    fileprivate var pending: PendingBinaryOperationInfo?
    
    
    struct PendingBinaryOperationInfo {
        var binaryFunction: ((Double, Double) -> Double)
        var fristOperand: Double
    }
    
    var result: Double {
        get {
            return accumulator
        }
    }
}




